package com.fp.m7.client.presenter;

import java.util.ArrayList;
import java.util.List;

import net.customware.gwt.presenter.client.EventBus;
import net.customware.gwt.presenter.client.widget.WidgetDisplay;
import net.customware.gwt.presenter.client.widget.WidgetPresenter;

import com.fp.m7.shared.Constants;
import com.fp.m7.shared.dto.CommentDto;
import com.fp.m7.shared.services.CommentServiceAsync;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.inject.Inject;
import com.google.inject.Provider;

/**
 * Timeline presenter displays the chronologic comment feed for an authorized user. One can navigate thru the comments
 * using arrow buttons.
 * 
 * @author 7
 */
public class TimelinePresenter extends WidgetPresenter<TimelinePresenter.Display> {

    public interface Display extends WidgetDisplay {

        HasWidgets getContentPanel();

        HasClickHandlers getPreviousButton();

        HasClickHandlers getNextButton();

    }

    /**
     * DI container injects a comment presenter provider, so that we can create and attach comment presenters from here
     * directly. Why here? Each comment is displayed according to MVP. So it has the 'presenter' part which handles
     * logic behavior, and it has the 'view' part which delivers the eye-candy. Because there are lots of comments -
     * there ale lots of presenters and their view widgets.
     */
    private Provider<CommentPresenter> commentPresenterProvider;
    private List<CommentPresenter> commentPresenters = new ArrayList<CommentPresenter>(Constants.MAX_COMMENTS_PER_PAGE);

    private CommentServiceAsync commentService;

    private Integer pageNo;

    private AsyncCallback<List<CommentDto>> commentCallback = new AsyncCallback<List<CommentDto>>() {
        @Override
        public void onSuccess(List<CommentDto> list) {
            clearComments();

            for (CommentDto commentDto : list) {
                CommentPresenter cp = commentPresenterProvider.get();
                cp.setCommentDto(commentDto);
                cp.bind();

                commentPresenters.add(cp);
                display.getContentPanel().add(cp.getDisplay().asWidget());
            }
        }

        @Override
        public void onFailure(Throwable throwable) {
            clearComments();
        }
    };

    @Inject
    public TimelinePresenter(Display display, EventBus eventBus, //
            Provider<CommentPresenter> commentPresenterProvider, //
            CommentServiceAsync commentService) {

        super(display, eventBus);

        this.commentPresenterProvider = commentPresenterProvider;
        this.commentService = commentService;
    }

    @Override
    protected void onBind() {
        display.getPreviousButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent paramClickEvent) {
                if (pageNo == null) {
                    pageNo = 0;
                } else if (pageNo > 0) {
                    --pageNo;
                    fetchComments();
                }
            }
        });

        display.getNextButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent paramClickEvent) {
                if (pageNo == null) {
                    pageNo = 1;
                } else {
                    ++pageNo;
                }
                fetchComments();
            }
        });
    }

    @Override
    protected void onUnbind() {
        clearComments();
    }

    @Override
    protected void onRevealDisplay() {
        fetchComments();
    }

    private void fetchComments() {
        int pageNumber = pageNo == null ? 0 : pageNo;
        commentService.timeline(pageNumber, commentCallback);
    }

    private void clearComments() {
        display.getContentPanel().clear();
        for (CommentPresenter cp : commentPresenters) {
            cp.unbind();
        }
        commentPresenters.clear();
    }

    public Integer getPageNo() {
        return pageNo;
    }

    public void setPageNo(Integer pageNo) {
        this.pageNo = pageNo;
    }

}
